682. Сумма на отрезке

 

Задан набор чисел a1, ..., an. Для заданных индексов l и r найдите

 

Вход. В первой строке записано количество чисел n (1 ≤ n ≤ 106). Во второй строке записаны числа ai (1 ≤ ai ≤ 1000), разделенные пробелом. В третьей строке записано количество запросов m (1 ≤ m ≤ 106). Далее на отдельных строках записаны сами запросы li и ri (1 ≤ lirin).

 

Выход. Выведите в отдельных строках m чисел Sli..ri.

 

Пример входа

Пример выхода

5

1 2 3 4 5

5

1 5

2 3

3 4

2 5

1 4

15

5

7

14

10

 

 

 

РЕШЕНИЕ

частичные суммы

 

Анализ алгоритма

Каждый запрос Sl,r можно выполнять при помощи цикла за время O(n). Имеется m ≤ 106 запросов, длина массива составляет n ≤ 106. При линейном времени выполнения запроса нам потребуется не более n * m ≤ 1012 операций, что даст Time Limit.

Рссмотрим частичные суммы массива а:

s1 = a1;

s2 = a1 + a2;

s3 = a1 + a2 + a3;

. . .

sn = a1 + a2 + a3 + . . . + an;

Вычислить значения s1, s2, …, sn можно в линейном массиве s за время O(n).

Далее заметим, что

Sl,r = al + al + 1 + … + ar =

=  (a1 + … + al + al + 1 + … + ar) – (a1 + … + al-1) = srsl-1

Таким образом ответить на запрос Sl,r можно за O(1), то есть за константное время.

 

Пример

Вычислим сумму a3 + a4 + a5 для приведенного в условии примера.

Имеем: a3 + a4 + a5 = s5s2 = 15 – 3 = 12.

 

Реализация алгоритма

Объявим два рабочих двумерных массива.

 

#define MAX 1000001

int a[MAX], s[MAX];

 

Читаем входной набор чисел в массив a, вычисляем частичные суммы в массиве s.

 

scanf("%d",&n);

s[0] = 0;

for(i = 1; i <= n; i++)

{

  scanf("%d",&a[i]);

  s[i] = s[i-1] + a[i];

}

 

Обрабатываем m запросов.

 

scanf("%d",&m);

for(i = 0; i < m; i++)

{

  scanf("%d %d",&b,&c);

  printf("%d\n",s[c] - s[b-1]);

}

 

Реализация алгоритма – SQRT декомпозиция - TLE

 

#include <cstdio>

#include <cmath>

#include <vector>

using namespace std;

 

int i, n, m, len, x, y;

vector<int> a, b;

 

int q(int l, int r)

{

  int i, sum = 0;

  int c_l = l / len, c_r = r / len;

  if (c_l == c_r)

    for (i = l; i <= r; i++)

      sum += a[i];

  else

  {

    for (i = l; i <= (c_l + 1)*len - 1; i++)

      sum += a[i];

    for (i = c_l + 1; i <= c_r - 1; i++)

    sum += b[i];

    for (i = c_r * len; i <= r; i++)

      sum += a[i];

  }

  return sum;

}

 

int main(void)

{

  scanf("%d", &n);

  a.resize(n);

  for (i = 0; i < n; i++)

    scanf("%d", &a[i]);

 

  len = sqrt(n) + 1;

  b.resize(len);

  for (i = 0; i < n; i++)

    b[i / len] += a[i];

 

  scanf("%d", &m);

  for (i = 0; i < m; i++)

  {

    scanf("%d %d", &x, &y);

    printf("%d\n", q(x - 1, y - 1));

  }

  return 0;

}

 

Реализация алгоритма – запрос за линейное время - TLE

 

#include <stdio.h>

#define MAX 1000001

 

int i, j, n, m, b, c, s;

int a[MAX];

 

int main(void)

{

  scanf("%d", &n);

  for (i = 1; i <= n; i++)

    scanf("%d", &a[i]);

 

  scanf("%d", &m);

  for (i = 0; i < m; i++)

  {

    scanf("%d %d", &b, &c);

    s = 0;

    for (j = b; j <= c; j++)

      s = s + a[j];

    printf("%d\n", s);

  }

  return 0;

}

 

Python реализация

Читаем входные данные.

 

n = int(input())

a = [0] + list(map(int, input().split()))

 

В списке s вычисляем частичные суммы списка а.

 

s = [0] * (n + 1)

for i in range(1, n + 1):

  s[i] = s[i - 1] + a[i]

 

Обрабатываем m запросов.

 

m = int(input())

for _ in range(m):

  b, c = map(int, input().split())

  print(s[c] - s[b - 1])